package universe;
import interfaces.ActionInterface;

import interfaces.AgentInterface;
import interfaces.WorldInterface;
import interfaces.WorldNodeInterface;
import interfaces.impl.Action;
import interfaces.impl.Agent;

import java.awt.Color;
import java.awt.Graphics;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.naming.spi.ObjectFactory;
import javax.swing.ImageIcon;



import extra.Position;
import factory.Constants;
import factory.ConstantsFactory;

import factory.WorldInterfaceFactory;



import objects.ImageObject;
import objects.WorldObject;


public class Universe {
	
	private WorldInterface worldI;
	
	
	private int height;
	private int width;

	private ArrayList<WorldObject> listObjects;
	private ArrayList<WorldObject> listObjectsToPaint;

	
	private ArrayList<WorldObject> listObjectsToKill;
	private ArrayList<WorldObject> listObjectsToAdd;
	
	BufferedImage b;
	
	public Universe(int width,int height){
		this.height=height;
		this.width=width;
		
		worldI = WorldInterfaceFactory.createNewWorldInterface(ConstantsFactory.WORLD_FIRST, width, height);
		
		listObjects = new ArrayList<WorldObject>();
	
		listObjectsToKill= new ArrayList<WorldObject>();
		listObjectsToAdd = new ArrayList<WorldObject>();
		listObjectsToPaint = new ArrayList<WorldObject>();
	}
	
	
	public void CalculateImageIntersection(WorldObject image){
		worldI.calculateCollision(image.getImageObject());
	}


	public void paint(Graphics g) {
		g.clearRect(0, 0, 600, 600);
		

		worldI.paint(g);
		g.drawImage(b, 35, 35, null);
		  
		
	}


	
	public void addObjectCopy(WorldObject object){
		System.out.println("agrego objetos");
		listObjects.add(new WorldObject(object));
	}
	

	public int getHeight() {
		return height;
	}


	public int getWidth() {
		return width;
	}

	public String saveFile(String save) {
		//saving the world's boxes
		save =width+","+height+System.getProperty("line.separator");
		//save =  world.save(save);
			
		//saving the world objects
		
		Iterator it = listObjects.iterator();
		while (it.hasNext()){
			WorldObject object = (WorldObject) it.next();
			save=object.save(save);
		}
		//System.out.println(save);
		
		return save;
	}


	public void loadFile(String name) {
		InputStreamReader isr;
		String line;
		int x,y;
		try {
			System.out.println("Cargo mundo");
			isr = new InputStreamReader( new FileInputStream((name)));
			BufferedReader input = new BufferedReader(isr);
			
			line=input.readLine();
			String [] linesElements =  line.split(",");
			width=Integer.parseInt(linesElements[0]);
			height=Integer.parseInt(linesElements[1]);
			worldI = WorldInterfaceFactory.createNewWorldInterface(ConstantsFactory.WORLD_FIRST, width, height);
			
			WorldObject object= new WorldObject();
			
			while((line=input.readLine())!=null){
				linesElements = line.split(",");
				
				if(Integer.parseInt(linesElements[0])==Constants.OBJECT_WORLD_ID){
					object = object.load(linesElements, 1);
				
					listObjects.add(object);
					for(WorldObject obj : object.getListObjects()){
						if(obj.isActive()){
							listObjects.add(obj);
						}
					}
				}
				
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
		
	public ArrayList<WorldObject> getListObjects() {
		return listObjects;
	}


	public void setListObjects(ArrayList<WorldObject> listObjects) {
		this.listObjects = listObjects;
	}

	public WorldObject clickObject(int x, int y) {
		
		WorldObject obj=new WorldObject();
		boolean found =false;
		
		for(WorldObject i : listObjects){
			if(x>i.getImageObject().getPosition().getX() &&y>i.getImageObject().getPosition().getY()){
				if(x<(i.getImageObject().getImageToShow().getWidth()+i.getImageObject().getPosition().getX()) && y<(i.getImageObject().getImageToShow().getHeight()+i.getImageObject().getPosition().getY())){
					Graphics graph;
					BufferedImage image = new BufferedImage(i.getImageObject().getImageToShow().getWidth(),i.getImageObject().getImageToShow().getHeight(),BufferedImage.TYPE_INT_RGB);
					graph= image.createGraphics();
					graph.setColor(new Color(237,2,53));
					graph.fillRect(0, 0, i.getImageObject().getImageToShow().getWidth(), i.getImageObject().getImageToShow().getHeight());
					graph.drawImage(i.getImageObject().getImageToShow(), 0, 0, null);
					if(image.getRGB(x-(int)i.getImageObject().getPosition().getX(), y-(int)i.getImageObject().getPosition().getY())!=graph.getColor().getRGB()){
						if(obj.compareTo(i)<0){
							obj = i;
							found=true;
						}
					}
				}
			}
			
		}
		if(!found){
			return null;
			}
		else{
			return obj;
		}
		
	}

	public ArrayList<WorldObject> getObjects(double x, double y, double x1, double y1, int idObjtectToSearch) {
		ArrayList<WorldObject> list = new ArrayList<WorldObject>();
		for(WorldObject obj : listObjects){
			if(obj.getObjectReference()!=idObjtectToSearch){
				continue;
			}
			if(obj.getPosition().getX()>x && obj.getPosition().getY()>y && obj.getPosition().getX()<x1 && obj.getPosition().getY()<y1){
				list.add(obj);
			}
		}
		return list;
	}

	private void searchActiveObject(WorldObject obj){
	
		for(WorldObject object : obj.getListObjects()){
			if(object.isActive() && !listObjects.contains(object)){
				listObjectsToAdd.add(object);
			}
			searchActiveObject(object);
		}
	}
	
	
	private void processEachObjectAction(double dTime, WorldObject obj){
		if(!obj.processNormalActions(dTime, this)){
			obj.processImmediatlyActions(dTime, this);
		}
		
		if(obj.isVisible() && !listObjectsToPaint.contains(obj)){
			listObjectsToPaint.add(obj);
		}
		
		for(WorldObject object : obj.getListObjects()){
			processEachObjectAction(dTime, object);
		}
	}
	
	public void update(double dTime) {
		freeCollisions(); //TODO change because now is in server and i dont have yet the images
		
		for(WorldObject obj : listObjects){
			searchActiveObject(obj);
		}
		
		for(WorldObject obj : listObjects){
			
			for(AgentInterface ag : obj.getListAgents()){
				ag.update(obj, this, dTime);
			}
			obj.processAgentsToRemove();
			
			//worldI.calculateCollision(obj.getImageObject());
			
		}
		
		for(WorldObject obj : listObjects){
			processEachObjectAction(dTime, obj);
		}
		
		addListObjects();
		killListObjects();
		
	}
	
	private void freeCollisions() {
		worldI.freeCollisionsNodes();
		for(WorldObject obj : listObjects){
			worldI.calculateCollision(obj.getImageObject());
		}
		
	}
	
	private void killListObjects() {
	     for(WorldObject obj : listObjectsToKill){
	    	//I remove the object from the object list from the universe
	    	listObjectsToPaint.remove(obj); 
	    	if(listObjects.contains(obj)){
	    	   listObjects.remove(obj);
	    	}
	    	
	    	//i remove the object from the fathers
	    	for(WorldObject object : obj.getListFather()){
	    		   object.getListObjects().remove(obj);
	    	}
	    	
	    	//i remove the object as a father from their listfathers
	    	for(WorldObject object : obj.getListObjects()){
	    		   object.getListFather().remove(obj);
	    	}
	    	
	     }
		listObjectsToKill.clear();
	}


	private void addListObjects() {
			for(WorldObject obj : listObjectsToAdd){
				if(!listObjects.contains(obj)){
					listObjects.add(obj);
				}
		
			}
			listObjectsToAdd.clear();
	}


	public boolean isInside(Position position){
		return worldI.isInside(position);
	}




	public boolean isFree(int x1, int y1) {
		// TODO Auto-generated method stub
		return worldI.isFree(new Position(x1,y1));
	}


	public boolean collition(WorldObject imageObject) {
		// TODO Auto-generated method stub
		return false;
	}


	public WorldInterface getWorldI() {
		return worldI;
	}


	public void setWorldI(WorldInterface worldI) {
		this.worldI = worldI;
	}


	public ArrayList<WorldObject> getListObjectsToKill() {
		return listObjectsToKill;
	}


	public void setListObjectsToKill(ArrayList<WorldObject> listObjectsToKill) {
		this.listObjectsToKill = listObjectsToKill;
	}


	public ArrayList<WorldObject> getListObjectsToAdd() {
		return listObjectsToAdd;
	}


	public void setListObjectsToAdd(ArrayList<WorldObject> listObjectsToAdd) {
		this.listObjectsToAdd = listObjectsToAdd;
	}


	public int getScreenHeight() {
		// TODO Auto-generated method stub
		return 0;
	}


	public int getScreenWidth() {
		// TODO Auto-generated method stub
		return 0;
	}


	public void generateCollitions() {
		// TODO Auto-generated method stub
		
	}


	public ArrayList<WorldObject> getListObjectsToPaint() {
		// TODO Auto-generated method stub
		return (ArrayList<WorldObject>)listObjectsToPaint.clone();
	}


	public WorldObject getObject(int id) {
		for(WorldObject obj : listObjects){
			if(obj.getID()==id){
				return obj;
			}
		}
		return null;
	}
	
	
}
